package com.atguigu.gulimallcart.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.utils.R;
import com.atguigu.gulimallcart.feign.ProductFeignService;
import com.atguigu.gulimallcart.interceptor.CartInterceptor;
import com.atguigu.gulimallcart.service.CartService;
import com.atguigu.gulimallcart.to.UserInfoTo;
import com.atguigu.gulimallcart.vo.Cart;
import com.atguigu.gulimallcart.vo.CartItem;
import com.atguigu.gulimallcart.vo.SkuInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @ClassName CartServiceImpl
 * @Description TODO
 * @Detail detail
 * @Author MyPC
 * @Date 2020/7/13
 * @Version 1.0
 */
@Slf4j
@Service
public class CartServiceImpl implements CartService{
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    ProductFeignService productFeignService;

    @Autowired
    ThreadPoolExecutor executor;
    //购物车key前缀
    private final String CART_PREFIX="gulimall:cart:";
    @Override
    public CartItem addToCart(Long skuId, Integer num) throws ExecutionException, InterruptedException {
        //获取要操作的购物车
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        String cartItemString = (String) cartOps.get(skuId.toString());
        if(StringUtils.isEmpty(cartItemString)){
            //此商品此前还未添加购物车，需要进行存储
            CartItem cartItem = new CartItem();
            //2、异步远程调用商品服务，添加商品信息到购物车中
            CompletableFuture<Void> skuInfoFuture = CompletableFuture.runAsync(() -> {
                R r = productFeignService.getSkuInfo(skuId);
                SkuInfoVo skuInfo = new SkuInfoVo();
                if (r.getCode() == 0) {
                    skuInfo = r.getData("skuInfo", new TypeReference<SkuInfoVo>() {
                    });
                }
                cartItem.setCheck(true);
                cartItem.setCount(num);
                cartItem.setImage(skuInfo.getSkuDefaultImg());
                cartItem.setPrice(skuInfo.getPrice());
                cartItem.setSkuId(skuId);
                cartItem.setTitle(skuInfo.getSkuTitle());
            }, executor);

            //3、异步远程调用获取sku属性信息
            CompletableFuture<Void> skuAttrFuture = CompletableFuture.runAsync(() -> {
                List<String> skuSaleAttrValues = productFeignService.getSkuSaleAttrValues(skuId);
                cartItem.setSkuAttrs(skuSaleAttrValues);
            }, executor);
            //等待异步操作全部完成
            CompletableFuture.allOf(skuInfoFuture,skuAttrFuture).get();
            String string = JSON.toJSONString(cartItem);
            cartOps.put(skuId.toString(),string);
            return cartItem;
        }else {
            //此商品此前已经添加过购物车了，只需修改数量即可
            CartItem cartItem = JSON.parseObject(cartItemString, CartItem.class);
            cartItem.setCount(cartItem.getCount()+num);
            cartOps.put(skuId.toString(),JSON.toJSONString(cartItem));
            return cartItem;
        }
    }

    /**
     * 根据skuId查询购物车信息
     * @param skuId
     * @return
     */
    @Override
    public CartItem getCartInfoBySkuId(Long skuId) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        String cartItemString = (String) cartOps.get(skuId.toString());
        return JSON.parseObject(cartItemString,CartItem.class);
    }

    /**
     * 获取购物车所有数据
     *      1、用户未登录
     *          获取临时购物车数据
     *      2、用户已登录
     *          1、如果临时购物车有数据，合并临时购物车数据到在线购物车，并删除临时购物车的数据
     *          2、获取在线购物车
     * @return
     * @throws ExecutionException
     * @throws InterruptedException
     */
    @Override
    public Cart getCart() throws ExecutionException, InterruptedException {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        Cart cart=new Cart();
        if(userInfoTo.getUserId() !=null){
            //用户已登录的购物车key
            String cartKey=CART_PREFIX+userInfoTo.getUserId();
            //临时购物车key
            String itemCartKey=CART_PREFIX+userInfoTo.getUserKey();
            //1、合并临时购物车和在线购物车
            List<CartItem> cartItemList = getCartItemList(itemCartKey);
            if(cartItemList!=null && cartItemList.size()>0){
                //如果临时购物车有数据，则进行合并
                for (CartItem cartItem : cartItemList) {
                    addToCart(cartItem.getSkuId(),cartItem.getCount());
                }
                //清空临时购物车
               clearCart(itemCartKey);
            }
            //获取在线购物车
            List<CartItem> cartItems = getCartItemList(cartKey);
            cart.setItems(cartItems);
        }else {
            //用户未登录
            //取出临时购物车
            String cartKey=CART_PREFIX+userInfoTo.getUserKey();
            List<CartItem> cartItems = getCartItemList(cartKey);
            cart.setItems(cartItems);
        }
        return cart;
    }

    /**
     * 清空购物车
     * @param cartKey
     */
    @Override
    public void clearCart(String cartKey) {
        //删除临时购物车
        stringRedisTemplate.delete(cartKey);
    }

    /**
     * 实时更新商品的选中状态
     * @param skuId
     * @param check
     */
    @Override
    public void changeCheckStatus(Long skuId, Integer check) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        CartItem cartItem = getCartInfoBySkuId(skuId);
        cartItem.setCheck(check==1 ? true : false);
        String string = JSON.toJSONString(cartItem);
        cartOps.put(skuId.toString(),string);
    }

    /**
     * 实时改变商品数量
     * @param skuId
     * @param count
     */
    @Override
    public void changeCount(Long skuId, Integer count) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        CartItem cartItem = getCartInfoBySkuId(skuId);
        cartItem.setCount(count);
        String string = JSON.toJSONString(cartItem);
        cartOps.put(skuId.toString(),string);
    }

    /**
     * 根据商品id删除购物车商品数据
     * @param skuId
     */
    @Override
    public void deleteItem(Long skuId) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        cartOps.delete(skuId.toString());
    }

    /**
     * 获取用户选中的购物项
     * @return
     */
    @Override
    public List<CartItem> getCurrentUserCartItems() {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        if(userInfoTo.getUserId() == null){
            return null;
        }else {
            String cartKey=CART_PREFIX+userInfoTo.getUserId();
            //获取用户所有的购物项
            List<CartItem> cartItemList = getCartItemList(cartKey);
            List<CartItem> collect = cartItemList.stream().filter(item -> item.getCheck()).
                    map(item -> {
                        //远程调用商品服务获取商品价格，获取商品最新价格
                        BigDecimal price = productFeignService.price(item.getSkuId());
                        item.setPrice(price);
                        return item;
                    }).
                    collect(Collectors.toList());
            return collect;
        }
    }

    /**
     * 提取我们要操作的购物车
     * @return
     */
    private BoundHashOperations<String, Object, Object> getCartOps() {
        String cartKey="";
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        if(userInfoTo.getUserId() !=null){
            //用户已登录
            cartKey=CART_PREFIX+userInfoTo.getUserId();
        }else {
            //用户未登录
            cartKey=CART_PREFIX+userInfoTo.getUserKey();
        }
        //绑定一个hash操作，这样每次操作都是操作operations绑定的key的数据
        BoundHashOperations<String, Object, Object> operations = stringRedisTemplate.boundHashOps(cartKey);
        return operations;
    }

    /**
     * 获取购物车的所有商品
     * @param cartKey
     * @return
     */
    private List<CartItem> getCartItemList(String cartKey){
        BoundHashOperations<String, Object, Object> operations = stringRedisTemplate.boundHashOps(cartKey);
        List<Object> values = operations.values();
        List<CartItem> cartItems=null;
        if(values !=null && values.size()>0){
            cartItems = values.stream().map((value) -> {
                String cartItemString = (String) value;
                return JSON.parseObject(cartItemString, CartItem.class);
            }).collect(Collectors.toList());
            return cartItems;
        }
        return null;
    }
}
